
#pragma once

#include "tools/wrapper.h"
#include "variant_types.h"

#if defined(__GNUC__) || defined(__MINGW32__) || defined(__MINGW__)
    #pragma GCC diagnostic push
    #pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
    #pragma GCC diagnostic ignored "-Weffc++"
#endif


namespace tools{
    namespace variant_detail{

        struct IStep;

        struct DIRECT_REVERSE;
        struct DIRECT_NORMAL;
//--------------------------------------------------------------------------------------

        struct IStep : public VariantTypes
        {
            virtual bool operator==(const IStep& rhs)const=0;
            virtual IStep& operator=(const IStep& rhs)=0;
            virtual void        Right()=0;
            virtual void        Left()=0;
            virtual void*       GetVariant()=0;
            virtual const void* GetVariant()const=0;
            virtual const Str&  GetKey()const=0;
        };
//--------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------

        template<class Iterator, class Directly> struct BaseStep: IStep
        {
            typedef typename Iterator::value_type value_type;

            enum { eIS_NORMAL  = ::std::is_same<Directly,DIRECT_NORMAL>::value  };
            enum { eIS_REVERSE = ::std::is_same<Directly,DIRECT_REVERSE>::value };
            enum { eIS_VALID = eIS_NORMAL || eIS_REVERSE };
            static_assert(eIS_VALID, "Directly most be DIRECT_NORMAL or DIRECT_REVERSE");

            BaseStep(const Iterator& i): mIterator(i){}

            bool operator==(const BaseStep& rhs)const { return mIterator==rhs.mIterator; }
            virtual bool operator==(const IStep& rhs)const
            {
                const BaseStep& r = static_cast<const BaseStep&>(rhs);
                return operator==(r);
            }

            BaseStep& operator=(const BaseStep& rhs) { mIterator = rhs.mIterator; return *this; }
            virtual IStep& operator=(const IStep& rhs) 
            {
                const BaseStep& r = static_cast<const BaseStep&>(rhs);
                operator=(r);
                return *this;
            }
            virtual void  Right() { const Directly*const p = nullptr; MoveR(p); }
            virtual void  Left()  { const Directly*const p = nullptr; MoveL(p); }
        private:
            void MoveR(const DIRECT_NORMAL*const) { ++mIterator; }
            void MoveR(const DIRECT_REVERSE*const){ --mIterator; }
            void MoveL(const DIRECT_REVERSE*const){ ++mIterator; }
            void MoveL(const DIRECT_NORMAL*const) { --mIterator; }
        protected:
            Iterator mIterator;
        };

        template<class Iterator, class Directly, int TYPE_CATEGORY> struct Step: BaseStep<Iterator, Directly>
        {
            typedef BaseStep<Iterator, Directly> Parent;
            typedef typename Iterator::value_type Type;

            Step(const Iterator& i): Parent(i){}

            virtual const V::Str& GetKey()const
            {
                const void*const element = this->mIterator.operator ->();
                return GetElement<Type,TYPE_CATEGORY>::GetKey(element);
            }
            virtual const void* GetVariant()const
            {
                const void*const element = this->mIterator.operator ->();
                return GetElement<Type,TYPE_CATEGORY>::GetVariant(element);
            }
            virtual void* GetVariant() 
            {
                const Step& me = *this;
                return  const_cast< void* >(me.GetVariant());
            }
        };

        typedef Wrapper<IStep, eSIZE_BUFF_ITERATORS> Native;

    }//namespace variant_detail
}//namespace tools


#if defined(__GNUC__) || defined(__MINGW32__) || defined(__GNUC__)
    #pragma GCC diagnostic pop
#endif
